package pres.lzx.music;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import java.io.File;
import java.util.HashSet;
import java.util.Set;

import static pres.lzx.music.ConsoleUtil.clearLine;


public class AudioPlayer implements LineListener {

    private Clip clip;

    private File currentMusicFile;
    private boolean isPlay = false;

    private AudioPlayerListener listener;
    private final Set<AudioPlayerListener> listenerSet = new HashSet<>();



    public static void main(String[] args) {
        final AudioPlayer player = new AudioPlayer();
        File[] allMusic = getAllMusic(args[0]);
        System.out.println("----文件中所有歌曲----文件数量：" + allMusic.length);
        for (int i = 0; i < allMusic.length; i++) {
            System.out.println((i + 1) + "." + allMusic[i].getName());
        }
        for (File file : allMusic) {
            System.out.println("当前播放音乐：" + file.getName());
            player.play(file);
            //synchronized 的作用是获取锁，没有 synchronized 块会抛出异常

            clearLine();
        }


    }

    static File[] getAllMusic(String path) throws IllegalArgumentException {
        File directory = new File(path);
        if (!directory.isDirectory()) {
            throw new IllegalArgumentException("请输入正确文件夹路径！");
        }
        return directory.listFiles(new MusicFileFilter());
    }

    public void play() {
        try {
            if (currentMusicFile == null) {
                System.out.println("当前无播放的文件");
                return;
            }
            // 文件流
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(currentMusicFile);
            // 文件编码
            AudioFormat audioFormat = audioInputStream.getFormat();
            // 转换文件编码
            if (audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {

                int frameSize = audioFormat.getFrameSize();
                if (audioFormat.getFrameSize() == AudioSystem.NOT_SPECIFIED) {
                    frameSize = audioFormat.getChannels() * 2;
                }

                audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, audioFormat.getSampleRate(), 16, audioFormat.getChannels(), frameSize, audioFormat.getSampleRate(), false);
                // 将数据流也转换成指定编码
                audioInputStream = AudioSystem.getAudioInputStream(audioFormat, audioInputStream);
            }

            // 打开输出设备
            DataLine.Info dataLineInfo = new DataLine.Info(Clip.class, audioFormat, AudioSystem.NOT_SPECIFIED);
            // 使数据行得到一个播放设备
            clip = (Clip) AudioSystem.getLine(dataLineInfo);
            clip.addLineListener(this);
            // 将数据行用指定的编码打开
            clip.open(audioInputStream);
            // System.out.println(AudioUtil.getDurationFormatString(clip.getMicrosecondLength(), AudioUtil.TimeUnit.MICROSECOND));

            // 使数据行得到数据时就开始播放
            clip.start();

            // 等待音乐播放完毕
            synchronized (this) {
                this.wait();
            }

        } catch (Exception e) {
            e.printStackTrace();
            this.notifyAll();
        }
    }

    public void play(File file) {
        this.currentMusicFile = file;
        play();
    }

    public void play(String filePath) {
        play(new File(filePath));
    }

    public void addEventListener(AudioPlayerListener audioPlayerListener) {
        if (listenerSet.size() > 1) {
            // TODO
            System.out.println("当前只支持添加一个监听器");
            return;
        }
        listenerSet.add(audioPlayerListener);
    }

    @Override
    public void update(LineEvent event) {
        System.out.println(event.getType());
        // 停止播放音乐
        if (LineEvent.Type.STOP == event.getType()) {
            // 音乐播放线程，如果有异常会被吞掉，导致后续代码无法执行
            listenerSet.forEach(AudioPlayerListener::onStop);
            clear();
            // 唤醒等待线程，用于继续播放一首
            synchronized (this) {
                this.notifyAll();
            }
            return;
        }
        // 开始播放音乐
        if (LineEvent.Type.START == event.getType()) {
            listenerSet.forEach(AudioPlayerListener::onPlay);
        }
    }

    private void clear() {
        if (clip != null && clip.isRunning()) {
            clip.drain();
            clip.close();
        }
    }
}
